home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
mailconf
/
alias.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-25
|
11KB
|
511 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <sys/stat.h>
#include "mailconf.h"
#include "internal.h"
#include "../misc/misc.h"
#include "../dialog/dialog.h"
#include "../userconf/userconf.h"
#include "../netconf/netconf.h"
#include "../paths.h"
#include "mailconf.m"
static MAILCONF_HELP_FILE help_aliases("aliases");
static CONFIG_FILE f_aliases (ETC_ALIASES,help_aliases
,CONFIGF_MANAGED|CONFIGF_OPTIONNAL);
class ALIAS: public ARRAY_OBJ{
SSTRING name;
SSTRINGS values;
SSTRING comment;
SSTRING filter;
SSTRING file;
/*~PROTOBEG~ ALIAS */
public:
ALIAS (char *line);
ALIAS (void);
private:
void addoneval (const char *val);
public:
int edit (void);
int file_ok (void);
int filter_ok (void);
const char *getname (void);
int is_valid (void);
private:
void splitline (char *ptpt);
public:
void write (FILE *fout);
/*~PROTOEND~ ALIAS */
};
PUBLIC ALIAS::ALIAS()
{
}
static char *str_copyupto (char *dest, const char *src, char stop)
{
while (isgraph(*src) && *src != stop) *dest++ = *src++;
*dest = '\0';
return ((char*) src);
}
/*
Add one element of the alias list
*/
PRIVATE void ALIAS::addoneval(const char *val)
{
char *pt = str_skip (val);
if (pt[0] == '|'){
pt++;
filter.setfrom (str_skip(pt));
}else if (strncmp(val,":include:",9)==0){
file.setfrom(val+9);
}else{
values.add (new SSTRING(val));
}
}
/*
Parse an alias list
*/
PRIVATE void ALIAS::splitline(char *ptpt)
{
/* #Specification: mailconf / alias / limits
We assume that an alias list has at most
one command redirection and one include file.
It may have as many other element (email address)
as needed.
*/
while (1){
ptpt = str_skip (ptpt);
if (ptpt[0] == '\0'){
break;
}else if (ptpt[0] == ','){
ptpt++;
}else if (ptpt[0] == '"'){
char word[200];
ptpt++;
char *ptw = word;
while (*ptpt != '\0' && *ptpt != '"') *ptw++ = *ptpt++;
*ptw = '\0';
if (*ptpt == '"') ptpt++;
addoneval (word);
}else{
char word[200];
ptpt = str_copyupto (word,ptpt,',');
addoneval(word);
}
}
}
/*
Used when reading the /etc/aliases file
line will be trashed.
*/
PUBLIC ALIAS::ALIAS(char *line)
{
char *pt = str_skip(line);
if (pt[0] == '#'){
comment.setfrom (pt);
}else{
char *ptpt = strchr(pt,':');
if (ptpt != NULL){
*ptpt++ = '\0';
strip_end (pt);
name.setfrom (pt);
splitline (ptpt);
}
}
}
PUBLIC const char *ALIAS::getname()
{
return name.get();
}
PUBLIC int ALIAS::filter_ok()
{
if (!filter.is_empty()){
/* #Specification: mailconf / aliases / filter program
Linuxconf assumes the first word of the filter part of an
alias is the program name (with or without path). It will
check if the path exist either as is, or in /bin or /usr/bin.
It will send a warning if the program can't be found.
Complex script can be entered here and linuxconf may be
fooled by this. It will just print a warning anyway
and the alias will be accepted.
If the program can be located, linuxconf will check that
it is indeed executable.
*/
char prog[PATH_MAX],binprog[PATH_MAX],usrbinprog[PATH_MAX];
str_copyword(prog,filter.get());
sprintf (binprog,"/bin/%s",prog);
sprintf (usrbinprog,"/usr/bin/%s",prog);
struct stat st;
if (stat (prog,&st) == -1
&& stat (binprog,&st) == -1
&& stat (usrbinprog,&st) == -1){
xconf_notice (MSG_U(N_MISSING,"%s does not exist"),prog);
}else if ((st.st_mode & 0111)==0){
xconf_notice (MSG_U(N_NOEXEC,"%s is not executable"));
}
}
return 1;
}
PUBLIC int ALIAS::file_ok()
{
/* #Specification: mailconf / aliases / in a file
When the user specify the indirect file for aliases
mailconf check if the file exist and send a notice
to the user if this is not the case. The
operation is accepted anyway.
*/
if (!file.is_empty()){
if (!file_exist(file.get())){
xconf_notice (MSG_R(N_MISSING),file.get());
}
}
return 1;
}
/*
Write one record
*/
PUBLIC void ALIAS::write (FILE *fout)
{
if (!name.is_empty()){
fprintf (fout,"%s: ",name.get());
char *comma = " ";
if (!filter.is_empty()){
fprintf (fout,"\"| %s\" ",filter.get());
comma = ",";
}
if (!file.is_empty()){
fprintf (fout,"%s:include:%s ",comma,file.get());
comma = ",";
}
int nb = values.getnb();
for (int i=0; i<nb; i++){
SSTRING *s = values.getitem(i);
if (!s->is_empty()){
fprintf (fout,"%s%s ",comma,s->get());
if (i > 0 && i % 4 == 0){
fputc ('\n',fout);
comma = "\t,";
}else{
comma = ",";
}
}
}
}
fprintf (fout,"%s\n",comment.get());
}
/*
Is it a valid record or a comment
*/
PUBLIC int ALIAS::is_valid()
{
return !name.is_empty();
}
/*
Edit an alias definition.
Return -1 if the user abort the edition (The record is left
unchanged then).
Return 0 if the user accepted the changes
Return 1 if the user request the deletion of this record
*/
PUBLIC int ALIAS::edit()
{
DIALOG dia;
dia.newf_str (MSG_U(F_ALIASNAME,"alias name"),name);
dia.newf_str (MSG_U(F_FILTER,"Filter program"),filter);
dia.newf_str (MSG_U(F_LISTFILE,"List file"),file);
/* #Specification: mailconf / aliases / limitation
The user interface present minimally 10 lines
for defining one alias value. A button ADD allows
the user to get more lines.
*/
dia.newf_title ("","");
int i;
for (i=values.getnb(); i<10; i++) values.add (new SSTRING);
int vnb = values.getnb();
for (i=0; i<vnb; i++){
dia.newf_str ("",*values.getitem(i));
}
int no = 0;
int ret = -1;
while (1){
MENU_STATUS code = dia.edit (
MSG_U(T_ONEALIAS,"One alias definition")
,MSG_U(I_ONEALIAS
,"Use the button ADD to get more space\n"
"in case you are defining a mailing list\n")
,help_aliases.getpath()
,no
,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_ADD|MENUBUT_DEL);
if (code == MENU_ESCAPE || code == MENU_CANCEL){
break;
}else if (code == MENU_DEL){
if (xconf_areyousure(MSG_U(Q_DELENTRY
,"Confirm deletion of this entry"))){
ret = 1;
break;
}
}else if (code == MENU_ADD){
int curnb = values.getnb();
for (i=0; i<10; i++) values.add (new SSTRING);
vnb = values.getnb();
for (i=curnb; i<vnb; i++){
dia.newf_str ("",*values.getitem(i));
}
}else if (code == MENU_ACCEPT
&& perm_rootaccess(MSG_U(P_EDITALIAS,"edit an alias"))){
if (name.is_empty()){
no = 0;
xconf_error (MSG_U(E_NONAME,"You must provide a name"));
}else if (!filter_ok()){
no = 1;
}else if (!file_ok()){
no = 1;
}else if (!filter.is_empty()
|| !file.is_empty()){
ret = 0;
break;
}else{
for (i=0; i<vnb; i++){
if (!values.getitem(i)->is_empty()){
break;
}
}
if (i == vnb){
xconf_error (MSG_U(E_ALLEMPTY,"All values are empty"));
no = 4;
}else{
ret = 0;
break;
}
}
}
}
if (ret == 0){
setmodified();
}else{
dia.restore();
}
return ret;
}
class ALIASES: public ARRAY{
/*~PROTOBEG~ ALIASES */
public:
ALIASES (void);
private:
void addline (char *buf);
public:
void addnew (void);
private:
int collect (const char **tb);
public:
void edit (void);
ALIAS *getitem (int no);
int locate (const char *name);
void write (void);
/*~PROTOEND~ ALIASES */
};
PUBLIC ALIAS *ALIASES::getitem(int no)
{
return (ALIAS*)ARRAY::getitem(no);
}
PRIVATE void ALIASES::addline (char *buf)
{
if (buf[0] != '\0') add (new ALIAS(buf));
buf[0] = '\0';
}
PUBLIC ALIASES::ALIASES()
{
FILE *fin = f_aliases.fopen ("r");
if (fin != NULL){
char buf[10000];
char line[1000];
buf[0] = '\0';
while (fgets(line,sizeof(line)-1,fin)!=NULL){
strip_end (line);
if (line[0] == '\0'){
addline (buf);
}else if (isspace(line[0])){
strcat (buf,line);
}else{
addline (buf);
strcpy (buf,line);
}
}
addline(buf);
rstmodified();
}
}
/*
Write back /etc/aliases
*/
PUBLIC void ALIASES::write ()
{
FILE *fout = f_aliases.fopen ("w");
if (fout != NULL){
for (int i=0; i<getnb(); i++){
getitem(i)->write(fout);
}
fclose (fout);
rstmodified();
/* #Specification: mailconf / aliases / updating
Whenever the /etc/aliases is updated,
the command "/usr/lib/sendmail -bi"
is executed.
*/
DAEMON *dae = daemon_find ("sendmail");
if (dae->is_managed()){
char cmd[200];
sprintf (cmd,"%s -bi",dae->getpath());
netconf_system (cmd);
}
}
}
/*
Find an alias in the table.
Return -1 if not found.
Return the index otherwise.
*/
PUBLIC int ALIASES::locate (const char *name)
{
int ret = -1;
int nb = getnb();
for (int i=0; i<nb; i++){
/* #Specification: mailconf / user aliases / case sensitivity
Email aliases are case insensitive and linuxconf properly
check for a duplicate using stricmp().
*/
if (stricmp(getitem(i)->getname(),name)==0){
ret = i;
break;
}
}
return ret;
}
/*
Add a new record
*/
PUBLIC void ALIASES::addnew()
{
ALIAS *a = new ALIAS;
while (a->edit()==0){
if (locate(a->getname())!=-1){
xconf_error (MSG_U(E_DUPALIAS,"Duplicate alias, rejected"));
}else{
add (a);
write();
a = NULL;
break;
}
}
delete a;
}
/*
Build the menuopt table for xconf_menu.
Return the number of line written.
if tb is NULL, just count the number of line.
tb will be sorted.
*/
PRIVATE int ALIASES::collect(const char **tb)
{
int count = 0;
int ii=0;
for (int i=0; i<nb; i++){
ALIAS *a = getitem(i);
if (a->is_valid()){
count++;
if (tb != NULL){
tb[ii++] = " ";
tb[ii++] = a->getname();
}
}
}
if (tb != NULL){
tb[ii] = NULL;
menuopt_sort (tb,count,1);
}
return count;
}
/*
Edit, add, delete record in the /etc/aliases file
*/
PUBLIC void ALIASES::edit()
{
int choice = 0;
while (1){
int nb = collect(NULL);
const char **menuopt
= (const char**)malloc(((nb*2)+1)*sizeof(char*));
collect(menuopt);
MENU_STATUS code = xconf_menu(
MSG_U(T_EDITALIASES,"Edit global mail aliases")
,MSG_U(IEDITALIASES
,"You are allowed to edit/add/deleted\n"
"system wide aliases for electronic mail")
,help_aliases
,NULL
,NULL
,NULL
,MSG_U(I_NEWALIAS,"new aliases")
,menuopt
,choice);
ALIAS *item = NULL;
if (choice >=0 && choice < nb){
item = getitem(locate(menuopt[choice*2+1]));
}
free ((char**)menuopt);
if (code == MENU_ESCAPE || code == MENU_QUIT){
break;
}else if (code == MENU_OK){
if (item != NULL){
int ok = item->edit();
if (ok != -1){
if (ok == 1) remove_del (item);
write();
}
}
}else if (perm_rootaccess(MSG_U(P_WRITE,"write %s"),f_aliases.getpath())){
if (code == MENU_ADD){
addnew();
}
}
}
}
void aliases_edit()
{
ALIASES al;
al.edit();
}